/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package fork;

import fork.nodeditor.NodeEditorGUI;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import tal.drivechain.chain.AbortChainException;
import tal.drivechain.chain.Chain;
import tal.drivechain.chain.ChainListener;
import tal.drivechain.chain.ChainNode;
import tal.drivechain.chain.NodeListener;
import tal.drivechain.gui.GUIModule;
import tal.drivechain.plugin.Channel;
import tal.drivechain.system.Globals;
import tal.drivechain.variable.SetProperty.Flag;
import tal.drivechain.variable.Variable;
import tal.drivechain.variable.types.DataType;

/**
 *
 * @author eisental
 */
public class NodeEditor extends GUIModule implements ChainListener, NodeListener {

    private Chain editChain;
    private ChainNode node;
    private NodeEditorGUI gui;
    public Font titleFont = new Font("Arial", Font.BOLD, 11);
    private Variable aboutVar = new Variable("about", DataType.STRING, null, true);

    @Override
    public void setupProperties() throws IllegalArgumentException, AbortChainException {
        gui = new NodeEditorGUI();
        component = gui;
        gui.init(color, this);
        super.setupProperties();
    }

    public void setEditChain(Object prop, Flag flag) {
        if (this.editChain!=null) this.editChain.removeChainListener(this);

        if (prop==null) editChain = Globals.getRootChain();
        else editChain = Globals.findChain((String)prop, null);

        this.editChain.addChainListener(this);
        this.editChain.addNodeListener(this);
        setNodeName(getNodeName(), null);
    } public String getEditChain() { return (editChain==null)?null:editChain.getPath(); }

    public void setNodeName(Object prop, Flag flag) {
        if (editChain!=null && prop!=null) {
            String sprop = (String)prop;
            node = editChain.getChild(sprop);
        } else node = null;
        try {
            gui.setNode(node);
        } catch (IllegalArgumentException e) {
            log("While setting module " + (node!=null?node.getName():"") + ": " + e.getMessage(), MSG.ERROR);
        }
    } public Object getNodeName() {
        if (node==null) return null;
        else return node.getName();
    }

    public void setWidth(Integer value, Flag flag) {
        Dimension d = new Dimension(value, component.getHeight());
        component.setSize(d);
        component.setPreferredSize(d);
    } public Integer getWidth() { return component.getWidth(); }

    public void setHeight(Integer value, Flag flag) {
        Dimension d = new Dimension(component.getWidth(), value);
        component.setSize(d);
        component.setPreferredSize(d);
    } public Integer getHeight() { return component.getHeight(); }

    @Override
    public void setFont(Font value) {
        super.setFont(value);
        gui.setFont(font);
    }

    @Override
    public void setColor(Color value) {
        super.setColor(value);
        gui.setColor(color);
    }

    public NodeEditorGUI getGUI() {
        return this.gui;
    }

    public ChainNode getNode() {
        return node;
    }

    public Chain getActualEditChain() {
        return editChain;
    }

    public void nodeRenamed(ChainNode src) {
        this.setEditChain(src.getPath(), null);
        gui.updateName(); // refresh the display just in case.
    }

    public void nodeMoved(ChainNode src) {
        this.setEditChain(src.getPath(), null);
    }

    @Override
    protected void msgReceived(Variable in, long timestamp, Channel channel) {    }

    public void chainStopped(Chain src) {}

    public boolean chainStopping(Chain src) { return true; }

    public boolean chainStarting(Chain src) { return true; }

    public void nodeConfigured(Chain src, ChainNode mod) {}

    public void childRemoved(Chain src, ChainNode m) {
        if (m==this.getNode()) this.setNodeName(null, null);
    }

    public void childAdded(Chain src, ChainNode m) {}

    public void messageReceived(ChainNode src, Variable var, Channel channel, long timestamp) {}

    public void messageSent(ChainNode src, Variable var, long timestamp) {}

    public void nameChanged(ChainNode src) {}

    public void metaChanged(ChainNode src) {}

    public void connectionsChanged(ChainNode src) {}

    public void nodeDestroyed(ChainNode src) {}

    public void propertyChanged(ChainNode src, String name, Object value) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void childRenamed(Chain src, ChainNode child) {}

    public void sendAboutMsg() {
        if (node==null || node instanceof Chain)
            log("Can't show module about since no node is selected or selected node is not a module.", MSG.ERROR);
        else {
            aboutVar.setValue(node.getNodeClassName(), true);
            sendToOutputs(aboutVar, -1);
        }
    }

    public void sendMessage(String text) {
        if (!editChain.isRunning()) {
            log("Can't send message while chain is closed.", MSG.ERROR);
            return;
        }

        try {
            Variable message = Variable.parseVariable("modboxMsg", null, text, false);
            if (message.isEvaluateAtHome()) message = message.evaluate(editChain);

            node.send(message, -1, Channel.CHAIN);
        } catch (IllegalArgumentException ie) {
            log("While creating variable: " + ie, MSG.ERROR);
        }

    }

}
